~ function() {
	class Drag extends UserCustomEvent {
		constructor(el, params) {
			super()
			this.initParams(el, params)
			this.setElementHandle()
			this.setContainment()
			this.bindEvent()
		}
		// 初始化参数
		initParams(el, params) {
			var options = {
				element: el, // 移动的元素
				handle: el, // 拖动的手柄
				axis: '', // 移动方向 x,y
				grid: null, // 网格 [20,20]
				containment: false, // 限制范围容器,true-限制到父级，string-class or id  elemet-DOM
			}
			Object.assign(this, options, params)
			return this
		}
		// 设置拖动元素和拖动手柄
		setElementHandle() {
			var {
				element,
				handle
			} = this
			this._element = Drag.isDOM(element) ? element : document.querySelector(element);
			this._handle = Drag.isDOM(handle) ? handle : document.querySelector(handle);
		}
		// 绑定事件
		bindEvent() {
			this.handleDown = this.handleDown.bind(this)
			this.handleMove = this.handleMove.bind(this)
			this.handleUp = this.handleUp.bind(this)
			this.resize = this.resize.bind(this)
			// _element的位置
			this.startPoint = {
				x: 0,
				y: 0
			}
			// 鼠标点击的位置
			this.mousePoint = {
				x: 0,
				y: 0
			}
			window.addEventListener('resize',Drag.throttle(this.resize,200))
			this._handle.addEventListener('mousedown', this.handleDown)
		}
		resize(){
			// 重新设置限制范围大小
			this.setContainment()
		}
		handleDown(ev) {
			ev.preventDefault()
			this.startPoint.x = this._element.offsetLeft
			this.startPoint.y = this._element.offsetTop
			this.mousePoint.x = ev.pageX
			this.mousePoint.y = ev.pageY
			// 点击鼠标，初始化_element偏移的位置
			this.offset = {
				x: 0,
				y: 0 
			}
			document.addEventListener('mousemove', this.handleMove)
			document.addEventListener('mouseup', this.handleUp)
			this.emit('dragStart',this,ev)
		}
		handleMove(ev) {
			this.offset.x = ev.pageX - this.mousePoint.x + this.startPoint.x
			this.offset.y = ev.pageY - this.mousePoint.y + this.startPoint.y

			// 设置网格
			this.setGrid()

			// 限制方向
			this.limitAxis()

			// 限制范围
			if(this.parent){
				this.setContainmentArea()
			}

			this.setValue(this.offset.x, this.offset.y)
			this.emit('dragMove',this,ev,this.offset)
		}
		handleUp(ev) {
			// 鼠标释放后，将transform偏移的值，增加到元素的left,top上，并清空transform
			Drag.css(this._element, {
				left:this.offset.x +"px",
				top:this.offset.y +"px",
				transform: ''
			})
			document.removeEventListener('mousemove', this.handleMove)
			document.removeEventListener('mouseup', this.handleUp)
			this.emit('dragEnd',this,ev,this.offset)
		}
		// 拖动设置transform的偏移值
		setValue(x, y) {
			Drag.css(this._element, {
				left:0,
				top:0,
				transform: `translate(${x}px,${y}px)`
			})
		}
		// 限制x,y轴
		limitAxis() {
			this.offset.y = this.axis === 'x' ? this.startPoint.y : this.offset.y
			this.offset.x = this.axis === 'y' ? this.startPoint.x : this.offset.x
		}
		// 设置网格
		setGrid() {
			var grid = this.grid
			if (!grid) return false
			var gridArr = []
			if (typeof grid === 'number') {
				gridArr = [grid, grid]
			} else if (typeof grid === 'object' && 'length' in grid && grid.length) {
				if (grid.length === 1) {
					gridArr = [grid[0], grid[0]]
				} else {
					gridArr = [grid[0], grid[1]]
				}
			}

			this.offset.x = this.setGridVal(gridArr[0], this.offset.x)
			this.offset.y = this.setGridVal(gridArr[1], this.offset.y)
		}
		/**
		 * 设置网格的位置
		 * @param {Object} grid 网格
		 * @param {Object} offset 偏移值
		 */
		setGridVal(grid, offset) {
			return Math.floor(offset / grid) * grid
		}
		// 设置容器的拖动最大值
		setContainment(){
			var containment = this.containment
			var _element = this._element
			if(!containment) return false;
			if (Drag.isBoolean(containment)) {
				this.parent = _element.parentNode;
			}else if(Drag.isString(containment) && document.querySelector(containment)){
				this.parent = document.querySelector(containment);
			}else if(Drag.isDOM(containment)){
				this.parent = containment
			}
			this.maxLeft = this.parent.offsetWidth  - _element.offsetWidth
			this.maxTop = this.parent.offsetHeight - _element.offsetHeight
		}
		// 设置容器范围
		setContainmentArea() {
			var left = this.offset.x
			var top = this.offset.y
			var maxLeft = this.maxLeft
			var maxTop = this.maxTop
			this.offset.x = left < 0 ? 0 : (left > maxLeft ? maxLeft : left);
			this.offset.y = top < 0 ? 0 : (top > maxTop ? maxTop : top);
		}
		static hasTouchEvent(){
			if('ontouchstart' in window){
				return true
			}
			return false
		}
		// 检测是否为dom元素
		static isDOM(obj) {
			return (Drag.isObject(HTMLElement) ?
				function() {
					return obj instanceof HTMLElement
				} :
				function() {
					return obj && typeof obj === 'object' && obj.nodeType === 1 && Drag.isString(obj.nodeName)
				})()
		}
		// 类型检测
		static isType() {
			var obj = {
				'isString': 'String',
				'isNumber': 'Number',
				'isArray': 'Array',
				'isObject': 'Object',
				'isBoolean': 'Boolean'
			}
			var _toString = obj.toString
			for (var key in obj) {
				this[key] = (function(key) {
					return function() {
						var reg = new RegExp("\\[object " + key + "\\]")
						return reg.test(_toString.call(arguments[0]))
					}
				})(obj[key])
			}

		}
		// 设置获取 css
		static css(el, attr, value) {
			if (typeof attr === 'string') {
				if (!value) return parseFloat(window.getComputedStyle(el)[attr])
				return el.style[attr] = value
			}
			if (typeof attr === 'object') {
				for (var key in attr) {
					el.style[key] = attr[key]
				}
			}
		}
		// 节流
		static throttle(fn,delay){
			var timer = null
			return function(){
				var context = this;
				var args = arguments
				if(!timer){
					timer = setTimeout(function(){
						timer = null
						fn.apply(context,args)
					},delay)
				}
				
			}
		}
	}
	Drag.isType()
	window.Drag = Drag
}()
